home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
CUGUK
/
PROG_TOO
/
C027B.ZIP
/
TOP
/
INST.C
< prev
next >
Wrap
Text File
|
1990-03-30
|
8KB
|
396 lines
/* Copyright (c) 1988 by Sozobon, Limited. Author: Tony Andrews
*
* Permission is granted to anyone to use this software for any purpose
* on any computer system, and to redistribute it freely, with the
* following restrictions:
* 1) No charge may be made other than reasonable charges for reproduction.
* 2) Modified versions must be clearly marked as such.
* 3) The authors are not responsible for any harmful consequences
* of using this software, even if they result from defects in it.
*/
/*
* Routines dealing with the parsing and output of instructions.
*/
#include "top.h"
static void getarg();
static int isreg();
/*
* addinst(bp, op, args) - add an instruction to block 'bp'
*/
void
addinst(bp, op, args)
register BLOCK *bp;
char *op, *args;
{
register INST *ni;
register int i;
register char *s;
char *arg2 = "";
if (*op == '\0') /* no instruction there */
return;
ni = (INST *) alloc(sizeof(INST));
ni->flags = 0;
ni->opcode = -1;
ni->next = NULL;
ni->prev = NULL;
ni->live = 0;
ni->rref = ni->rset = 0;
ni->src.areg = ni->dst.areg = 0;
ni->src.ireg = ni->dst.ireg = 0;
ni->src.disp = ni->dst.disp = 0;
ni->src.astr = ni->dst.astr = NULL;
ni->src.amode = ni->dst.amode = NONE;
/*
* Link into the block appropriately
*/
if (bp->first == NULL) {
bp->first = bp->last = ni;
} else {
bp->last->next = ni;
ni->prev = bp->last;
bp->last = ni;
}
for (s = op; *s ;s++) {
/*
* Pseudo-ops start with a period, so the length
* specifier can't be the first character.
*/
if (*s == '.' && s != op) { /* length specifier */
*s++ = '\0';
switch (*s) {
case 'b':
ni->flags |= LENB;
break;
case 'w':
ni->flags |= LENW;
break;
case 'l':
ni->flags |= LENL;
break;
default:
fprintf(stderr, "Bad length spec '%c'\n", *s);
exit(1);
}
}
}
for (i=0; opnames[i] ;i++) {
if (strcmp(op, opnames[i]) == 0) {
ni->opcode = i;
break;
}
}
if (ni->opcode < 0) {
fprintf(stderr, "Unknown op '%s'\n", op);
exit(1);
}
for (s = args; *s ;s++) {
/*
* skip chars in parens, since an operand split can't
* occur within.
*/
if (*s == '(') {
while (*s != ')')
s++;
}
if (*s == ',') {
*s++ = '\0';
arg2 = s;
break;
}
}
getarg(&ni->src, args);
getarg(&ni->dst, arg2);
}
/*
* delinst(bp, ip) - delete instruction 'ip' in block 'bp'
*/
void
delinst(bp, ip)
BLOCK *bp;
INST *ip;
{
INST *pi, *ni; /* previous and next instructions */
pi = ip->prev;
ni = ip->next;
if (pi != NULL)
pi->next = ni;
else
bp->first = ni;
if (ni != NULL)
ni->prev = pi;
else
bp->last = pi;
/*
* Free space used by the instruction.
*/
if (ip->src.astr != NULL)
free(ip->src.astr);
if (ip->dst.astr != NULL)
free(ip->dst.astr);
free(ip);
}
static void
getarg(op, s)
register struct opnd *op;
register char *s;
{
extern long atol();
register int reg;
register char *p;
if (*s == '\0') {
op->amode = NONE;
return;
}
if (*s == '#') { /* immediate data */
op->amode = IMM;
s += 1;
if (isdigit(s[0]) || s[0] == '-')
op->disp = atol(s);
else {
op->amode |= SYMB;
op->astr = strsave(s);
}
return;
} else if ((reg = isreg(s)) >= 0) { /* reg. direct */
op->amode = REG;
op->areg = reg;
} else if (s[0] == '(' || (s[0] == '-' && s[1] == '(')) {
op->amode = REGI;
if (s[0] == '-') {
op->amode |= DEC;
s++;
}
s++; /* skip the left paren */
if ((op->areg = isreg(s)) < 0) {
fprintf(stderr, "bad reg. '%s'\n", s);
exit(1);
}
s += 3; /* skip the register and right paren */
if (s[0] == '+')
op->amode |= INC;
} else if (!isdigit(s[0]) && (s[0] != '-')) {
op->amode = ABS;
op->astr = strsave(s);
} else {
for (p=s; isdigit(*p) || *p == '-' ;p++)
;
if (*p != '(') {
/*
* Must have been absolute, but with an
* address instead of a symbol.
*/
op->amode = ABS;
op->astr = strsave(s);
return;
}
*p++ = '\0';
op->disp = atol(s);
s = p;
if (s[0] == 'p' && s[1] == 'c') { /* PC relative */
if (s[2] == ')') {
op->amode = PCD;
return;
}
op->amode = PCDX;
op->ireg = isreg(s+3);
if (s[6] == 'l')
op->amode |= XLONG;
} else if ((reg = isreg(s)) >= 0) {
op->areg = reg;
if (s[2] == ')') {
op->amode = REGID;
return;
}
op->amode = REGIDX;
op->ireg = isreg(s+3);
if (s[6] == 'l')
op->amode |= XLONG;
} else {
fprintf(stderr, "bad reg. '%s' after disp\n", s);
exit(1);
}
}
}
/*
* characters that can terminate a register name
*/
#define isterm(c) ((c) == '\0' || (c) == ')' || (c) == ',' || (c) == '.')
static int
isreg(s)
char *s;
{
if (s[0] == 'd' && isdigit(s[1]) && isterm(s[2]))
return D0 + (s[1] - '0');
if (s[0] == 'a' && isdigit(s[1]) && isterm(s[2]))
return A0 + (s[1] - '0');
if (s[0] == 's' && s[1] == 'p' && isterm(s[2]))
return SP;
return -1;
}
/*
* Routines for printing out instructions
*/
static char *rstr();
static void putop();
void
putinst(ip)
register INST *ip;
{
char c;
fprintf(ofp, "\t%s", opnames[ip->opcode]);
switch (ip->flags) {
case LENB:
c = 'b';
break;
case LENW:
c = 'w';
break;
case LENL:
c = 'l';
break;
default:
c = '\0';
break;
}
if (c)
fprintf(ofp, ".%c", c);
if (ip->src.amode != NONE) {
fprintf(ofp, "\t");
putop(&ip->src);
}
if (ip->dst.amode != NONE) {
fprintf(ofp, ",");
putop(&ip->dst);
}
#ifdef DEBUG
if (debug)
fprintf(ofp, "\t\t* ref(%04x), set(%04x), live(%04x)",
reg_ref(ip), reg_set(ip), ip->live);
#endif
fprintf(ofp, "\n");
}
static void
putop(op)
register struct opnd *op;
{
switch (op->amode & MMASK) {
case NONE:
break;
case REG:
fprintf(ofp, "%s", rstr(op->areg));
break;
case IMM:
if (op->amode & SYMB)
fprintf(ofp, "#%s", op->astr);
else
fprintf(ofp, "#%ld", op->disp);
break;
case ABS:
fprintf(ofp, "%s", op->astr);
break;
case REGI:
if (op->amode & DEC)
fprintf(ofp, "-");
fprintf(ofp, "(%s)", rstr(op->areg));
if (op->amode & INC)
fprintf(ofp, "+");
break;
case REGID:
fprintf(ofp, "%ld(%s)", op->disp, rstr(op->areg));
break;
case REGIDX:
fprintf(ofp, "%ld(%s,", op->disp, rstr(op->areg));
fprintf(ofp, "%s.%c)", rstr(op->ireg),
(op->amode & XLONG) ? 'l' : 'w');
break;
case PCD:
fprintf(ofp, "%ld(pc)", op->disp);
break;
case PCDX:
fprintf(ofp, "%ld(pc,%s.%c)", op->disp, rstr(op->ireg),
(op->amode & XLONG) ? 'l' : 'w');
break;
default:
fprintf(stderr, "bad addr. mode in putop: %d\n", op->amode);
exit(1);
}
}
static char *
rstr(r)
register char r;
{
static char buf[3];
if (r == SP) {
buf[0] = 's';
buf[1] = 'p';
} else if (r >= A0 && r <= A6) {
buf[0] = 'a';
buf[1] = '0' + (r - A0);
} else {
buf[0] = 'd';
buf[1] = '0' + (r - D0);
}
buf[2] = '\0';
return buf;
}
/*
* opeq(op1, op2) - test equality of the two instruction operands
*/
bool
opeq(op1, op2)
struct opnd *op1, *op2;
{
if (op1->amode != op2->amode || op1->areg != op2->areg ||
op1->ireg != op2->ireg || op1->disp != op2->disp)
return FALSE;
if (op1->astr == NULL)
return (op2->astr == NULL);
else {
if (op2->astr == NULL)
return FALSE;
return (strcmp(op1->astr, op2->astr) == 0);
}
}